//
//  CJLabel.swift
//  TextKit
//
//  Created by Chris on 2017/9/17.
//  Copyright © 2017年 Chris. All rights reserved.
//

import UIKit

/// 使用 TextKit 管理Text的label
class CJLabel: UILabel {

    /// 文本属性存储
    fileprivate lazy var textStorage = NSTextStorage()
    /// 文本布局管理
    fileprivate lazy var layoutManager = NSLayoutManager()
    /// 文本绘制的范围
    fileprivate lazy var textContainer = NSTextContainer()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupTextKit()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupTextKit()
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        // 设置文本指定范围
        textContainer.size = bounds.size
    }
    
    /// 重写Text中didSet方法, 当内容改变时, 重新绘制文本
    override var text: String? {
        didSet {
            // 重新绘制文本
            setupTextKit()
        }
    }
    
    
    /// 对label进行文本绘制
    ///
    /// - Parameter rect: 文本区域
    override func drawText(in rect: CGRect) {
        let range = NSRange(location: 0, length: textStorage.length)
        
        // 绘制背景
        layoutManager.drawBackground(forGlyphRange: range, at: CGPoint.zero)
        // 绘制字体
        layoutManager.drawGlyphs(forGlyphRange: range, at: CGPoint.zero)
    }
    
    /// label点击事件
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        // 获取点击的Location
        guard let touchPoint = touches.first?.location(in: self) else {
            return
        }
        // 获取label点击文字的索引
        let idx = layoutManager.glyphIndex(for: touchPoint, in: textContainer)
        
        // 遍历链接数组, 判断点击的文本是否在 链接内
        for range in urlRanges ?? [] {
            if NSLocationInRange(idx, range) {
                // 点击在链接内, 修改链接样式
                textStorage.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: range)
                // 重新绘制label
                setNeedsDisplay()
                guard let url = URL(string: (textStorage.string as NSString).substring(with: range)) else {
                    continue
                }
                // 打开链接
                UIApplication.shared.open(url, options: [:], completionHandler: nil)
                break
            }
        }
    }
}

// MARK: - 设置TextKit中管理对象
fileprivate extension CJLabel {
    
    /// 设置TextKit中的文本以及对应关系
    func setupTextKit() {
        
        // 添加文本内容
        setupTextContainer()
        // 设置文本管理关系
        textStorage.addLayoutManager(layoutManager)
        layoutManager.addTextContainer(textContainer)
    }
    
    /// 设置文本绘制范围
    private func setupTextContainer() {
        // 设置文本内容
        if let attributedText = attributedText {
            textStorage.setAttributedString(attributedText)
        } else if let text = text {
            textStorage.setAttributedString(NSAttributedString(string: text))
        } else {
            textStorage.setAttributedString(NSAttributedString(string: ""))
        }
        
        // 打开用户交互
        isUserInteractionEnabled = true
        
        // 对匹配链接的文本进行操作
        for linkRange in urlRanges ?? [] {
            // 添加链接属性
            textStorage.addAttributes([
                NSForegroundColorAttributeName: UIColor.blue,
                NSUnderlineStyleAttributeName: NSNumber(value: 1)
                ], range: linkRange)
        }
    }
}

// MARK: - 处理文本的内容(链接)
fileprivate extension CJLabel {
    
    /// label中的链接NSRange数组
    var urlRanges: [NSRange]? {
        
        // 匹配字符串的链接正则表示式
        let pattern = "[a-zA-Z]*://[a-zA-Z0-9/\\.]*"
        // 匹配规则
        guard let regx = try? NSRegularExpression(pattern: pattern, options: []) else {
            return nil
        }
        // 匹配结果数组
        let matchs = regx.matches(in: textStorage.string, options: [], range: NSRange(location: 0, length: textStorage.length))
        
        var rangs = [NSRange]()
        // 遍历结果数组, 取出range保存到rangs中
        for match in matchs {
            rangs.append(match.rangeAt(0))
        }
        return rangs
    }
    
}
